/*
 * global.c
 *
 *  Created on: 2018年9月5日
 *      Author: ray
 */
// #include "include.h"
#include "global.h"
#include "TypeDefine.h"
#include "EditFrame.h"
// #include "SysVarDefine.h"
#include "stdlib.h"
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_timer.h"  // 包含获取系统时钟 tick 的函数声明
#include "ui.h"
#include "data.h"

static const char *TAG = "global ";

extern const Env_ST Env_st;

uint32_t Overtime_A20;
// uint32_t _gReceiveData;// 表示接收到了主机发送来的数据，波特率正常，用来自适应波特率用的，不用了
volatile uint32_t _gSysClock;         // 系统时间
// uint32_t uart_idle_delay;             // 串口空闲时间
uint16_t FrameState;                  // 数据帧状态
uint16_t NeedReadBytes = 1;           // 需要从fifo中读取的数据长度
uint16_t frame_length;                // 数据帧长度
uint8_t uart_addr;                    // 端口临时地址
uint32_t system_mode;                 // 系统工作模式，开机为0，申请地址为0x01~0x1F，申请成功为0x100
uint32_t FlashTime;                   // 闪灯频率
uint32_t _gDelayTime;                 // DO开关延时   
HistoryFrame_ST HistoryFrame_st[MaxHistoryFrame];

// 各个端口接收到的整包数据
uint8_t FrameBuf[MaxSubPortLength];

// Dev_Device_ST *pDevice = &Dev_Device_st; //定义设备指针

const uint16_t TableOfBaud[6] =
    {
        1152,
        576,
        384,
        192,
        96,
        48,
};
uint8_t CurrentBaudIndex[5];  // 当前端口波特率在上表中的索引

//////////////////////////////////////////////// CRC 校验 /////////////////////////////////////////////////////////////////////
const uint8_t Table_CRCLo[] = {0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, //
                             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};
const uint8_t Table_CRCHi[] = {0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, //
                             0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, //
                             0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, //
                             0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, //
                             0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, //
                             0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, //
                             0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, //
                             0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, //
                             0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, //
                             0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, //
                             0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, //
                             0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, //
                             0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, //
                             0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, //
                             0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, //
                             0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40};
/****************************************************************************
 * 函数名称：     CRCCheck
 * 功能描述：     计算一段连续代码的CRC校验
 * 函数类型：     全局函数
 **    输入：           uint8_t *pData,           待校验队列首地址指针
 uint32_t DataLength       数据长度
 **    输出：           无
 * 返回值     ：     uint16_t CRCValue     CRC 计算结果
 * 调用参数：
 * 创建人：          jiangzy
 * 创建日期：     20150802
 * 修改日期：
 ****************************************************************************/
uint16_t CRCCheck(uint8_t *pData, uint32_t DataLength)
{
    uint8_t CRCHi = 0xFF; // CRC 校验结果高位
    uint8_t CRCLo = 0xFF; // CRC 校验结果低位
    uint8_t Index = 0;    // CRC 查表索引
    uint16_t Result = 0;  // 计算结果

    // 循环计算CRC
    while (DataLength--)
    {
        // 计算下一个CRC 索引值，并且数据指针移位。
        Index = CRCLo ^ *pData++;
        CRCLo = CRCHi ^ Table_CRCLo[Index];
        CRCHi = Table_CRCHi[Index];
    }
    // 填写最终结果
    Result = (uint16_t)CRCHi;
    Result = Result << 8;
    Result |= (uint16_t)CRCLo;
    return Result;
}

/****************************************************************
 **描  述: 
	8bit和校验
 **输  入: 
	
 **输  出: 
	
 **返回值: 
	
 **Date: 2021-06-23 10:58:17
 **LastEditors: Ray
 **说  明: 
 **param {uint8_t} *pData
 **param {uint8_t} DataLength
*****************************************************************/
uint8_t CheckSum(uint8_t *pData, uint8_t DataLength)
{
    uint8_t sum;
    for (sum = 0; DataLength > 0; DataLength--)
    {
        sum += *pData++;
    }
    return sum;
}

/*--------------------------------------------------------------
 * 功能: 清空指定类型的设备的全部地址
 * 
 * 参数: COMx 
 * 参数: devType 
----------------------------------------------------------------*/
void RestoreFactory(uint32_t COMx, uint8_t devType)
{
    uint8_t temp;
    uint64_t sys_tick = esp_timer_get_time();
    srand((unsigned int)(sys_tick));
    
    switch (devType)
    {
        case emTypeML4: // 4路照明重新申请地址
            memset(bml04_info.devAddr, 0, sizeof(bml04_info.devAddr));
            bml04_info.devLEDtime = emFlashRequest;
            // bml04_info.devAddrNow = 0x00;
            bml04_info.dev_index = 0;
            bml04_info.dev_SCRindex = 0;
            memset(bml04_info.dev_Random_mode, 0, sizeof(bml04_info.dev_Random_mode));
            bml04_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            bml04_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            bml04_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", bml04_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, BML04_key);  // 清空保存的地址
            break;

        case emTypeML12: // 12路照明重新申请地址
            memset(bml12_info.devAddr, 0, sizeof(bml12_info.devAddr));
            bml12_info.devLEDtime = emFlashRequest;
            // bml12_info.devAddrNow = 0x00;
            bml12_info.dev_index = 0;
            bml12_info.dev_SCRindex = 0;
            memset(bml12_info.dev_Random_mode, 0, sizeof(bml12_info.dev_Random_mode));
            bml12_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            bml12_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            bml12_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", bml12_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, BML12_key);  // 清空保存的地址
            break;

        case emTypeMD8: // MD8重新申请地址
            memset(md8_info.devAddr, 0, sizeof(md8_info.devAddr));
            md8_info.devLEDtime = emFlashRequest;
            // md8_info.devAddrNow = 0x00;
            md8_info.dev_index = 0;
            md8_info.dev_SCRindex = 0;
            memset(md8_info.dev_DI_state, 0, sizeof(md8_info.dev_DI_state));
            md8_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            md8_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            md8_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", md8_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, MD8_key);    // 清空保存的地址
            break;
        
        case emTypeMA8: // MD8重新申请地址
            memset(ma8_info.devAddr, 0, sizeof(ma8_info.devAddr));
            ma8_info.devLEDtime = emFlashRequest;
            // ma8_info.devAddrNow = 0x00;
            ma8_info.dev_index = 0;
            ma8_info.dev_SCRindex = 0;
            memset(ma8_info.dev_Random_mode, 0, sizeof(ma8_info.dev_Random_mode));
            ma8_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            ma8_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            ma8_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", ma8_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, MA8_key);    // 清空保存的地址
            break;
        case emTypeM26: // M26重新申请地址
            memset(m26_info.devAddr, 0, sizeof(m26_info.devAddr));
            m26_info.devLEDtime = emFlashRequest;
            // m26_info.devAddrNow = 0x00;
            m26_info.dev_index = 0;
            m26_info.dev_SCRindex = 0;
            memset(m26_info.dev_DI_state, 0, sizeof(m26_info.dev_DI_state));
            memset(m26_info.dev_Random_mode, 0, sizeof(m26_info.dev_Random_mode));
            m26_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            m26_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            m26_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", m26_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, M26_key);    // 清空保存的地址
            break;
        case emTypeM38: // M38重新申请地址
            memset(m38_info.devAddr, 0, sizeof(m38_info.devAddr));
            m38_info.devLEDtime = emFlashRequest;
            // m38_info.devAddrNow = 0x00;
            m38_info.dev_index = 0;
            m38_info.dev_SCRindex = 0;
            memset(m38_info.dev_DI_state, 0, sizeof(m38_info.dev_DI_state));
            memset(m38_info.dev_Random_mode, 0, sizeof(m38_info.dev_Random_mode));
            m38_info.dev_state = devReqAddr;// 设置设备模式为申请地址
            m38_info.dev_flag = Info_noSave;
            temp = (uint32_t)rand() % (Env_st.MaxAddr + 1);
            if (temp == 0)
            {
                temp++;
            }
            // 设置临时地址
            m38_info.devAddrTemp = temp | 0x80;
            MY_INFO("devAddrTemp = 0X%02X", m38_info.devAddrTemp);
            NVS_data_erase_key(DEV_INFO_NAMESPACE, M38_key);    // 清空保存的地址
            break;
        
        default:
            break;
    }
}

/*--------------------------------------------------------------
 * 功能: Set the Address object
 * 
 * 参数: addr 主机发来的地址
 * 参数: devType 设备类型
----------------------------------------------------------------*/
void SetAddress(const uint8_t addr, uint8_t devType)
{    
    switch (devType)
    {
        case emTypeML4:
            if((bml04_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (bml04_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                bml04_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(bml04_info.dev_index < bml04_info.dev_num && bml04_info.devAddr[bml04_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<bml04_info.dev_num; i++)
                    {
                        if(addr == bml04_info.devAddr[i])
                        {
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, bml04_info.devAddr[i]);
                            return ;
                        }
                    }
                    bml04_info.devAddr[bml04_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", bml04_info.dev_index, bml04_info.devAddr[bml04_info.dev_index]);
                    bml04_info.dev_index++;
                    if(bml04_info.dev_index == bml04_info.dev_num && bml04_info.dev_index > 0)
                    {
                        bml04_info.dev_state = devRun;
                        bml04_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        bml04_saveinfo.saveflag = bml04_info.dev_flag;
                        bml04_saveinfo.saveNum = bml04_info.dev_num;
                        bml04_saveinfo.saveState = bml04_info.dev_state;
                        memcpy(bml04_saveinfo.saveAddr, bml04_info.devAddr, sizeof(bml04_saveinfo.saveAddr));
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, BML04_key, (uint8_t*)&bml04_saveinfo, sizeof(bml04_saveinfo));
                        for(uint8_t i=0; i<bml04_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, bml04_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;
        
        case emTypeML12:
            if((bml12_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (bml12_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                bml12_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(bml12_info.dev_index < bml12_info.dev_num && bml12_info.devAddr[bml12_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<bml12_info.dev_num; i++)
                    {
                        if(addr == bml12_info.devAddr[i])
                        {
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, bml12_info.devAddr[i]);
                            return ;
                        }
                    }
                    bml12_info.devAddr[bml12_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", bml12_info.dev_index, bml12_info.devAddr[bml12_info.dev_index]);
                    bml12_info.dev_index++;
                    if(bml12_info.dev_index == bml12_info.dev_num && bml12_info.dev_index > 0)
                    {
                        bml12_info.dev_state = devRun;
                        bml12_info.devLEDtime = emFlashRun;
                        bml12_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, BML12_key, (uint8_t*)&bml12_info, sizeof(bml12_info));
                        for(uint8_t i=0; i<bml12_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, bml12_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;

        case emTypeMD8:
            if((md8_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (md8_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                md8_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(md8_info.dev_index < md8_info.dev_num && md8_info.devAddr[md8_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<md8_info.dev_num; i++)
                    {
                        if(addr == md8_info.devAddr[i])
                        {
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, md8_info.devAddr[i]);
                            return ;
                        }
                    }
                    md8_info.devAddr[md8_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", md8_info.dev_index, md8_info.devAddr[md8_info.dev_index]);
                    md8_info.dev_index++;
                    if(md8_info.dev_index == md8_info.dev_num && md8_info.dev_index > 0)
                    {
                        md8_info.dev_state = devRun;
                        md8_info.devLEDtime = emFlashRun;
                        md8_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, MD8_key, &md8_info, sizeof(md8_info));
                        for(uint8_t i=0; i<md8_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, md8_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;
        
        case emTypeMA8:
            if((ma8_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (ma8_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                ma8_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(ma8_info.dev_index < ma8_info.dev_num && ma8_info.devAddr[ma8_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<ma8_info.dev_num; i++)
                    {
                        if(addr == ma8_info.devAddr[i])
                        {
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, ma8_info.devAddr[i]);
                            return ;
                        }
                    }
                    ma8_info.devAddr[ma8_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", ma8_info.dev_index, ma8_info.devAddr[ma8_info.dev_index]);
                    ma8_info.dev_index++;
                    if(ma8_info.dev_index == ma8_info.dev_num && ma8_info.dev_index > 0)
                    {
                        ma8_info.dev_state = devRun;
                        ma8_info.devLEDtime = emFlashRun;
                        ma8_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, MA8_key, &ma8_info, sizeof(ma8_info));
                        for(uint8_t i=0; i<ma8_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, ma8_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;
        
        case emTypeM26:
            if((m26_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (m26_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                m26_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(m26_info.dev_index < m26_info.dev_num && m26_info.devAddr[m26_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<m26_info.dev_num; i++)
                    {
                        if(addr == m26_info.devAddr[i])
                        {
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, m26_info.devAddr[i]);
                            return ;
                        }
                    }
                    m26_info.devAddr[m26_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", m26_info.dev_index, m26_info.devAddr[m26_info.dev_index]);
                    m26_info.dev_index++;
                    if(m26_info.dev_index == m26_info.dev_num && m26_info.dev_index > 0)
                    {
                        m26_info.dev_state = devRun;
                        m26_info.devLEDtime = emFlashRun;
                        m26_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, M26_key, &m26_info, sizeof(m26_info));
                        for(uint8_t i=0; i<m26_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, m26_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;
        case emTypeM38:
            if((m38_info.devAddrTemp & 0x80) == 0x80 &&   // 判断是不是临时地址
                addr == (m38_info.devAddrTemp & 0x7F) &&  // 判断主机回复的地址
                m38_info.dev_state == devReqAddr)         // 判断是不是申请地址
            {
                if(m38_info.dev_index < m38_info.dev_num && m38_info.devAddr[m38_info.dev_index] == 0x00)
                {
                    for(uint8_t i=0; i<m38_info.dev_num; i++)
                    {
                        if(addr == m38_info.devAddr[i])
                        {
                            // 过滤重复地址
                            MY_ERROR("addr = 0X%02X, devAddr[%d] = 0X%02X", addr, i, m38_info.devAddr[i]);
                            return ;
                        }
                    }
                    m38_info.devAddr[m38_info.dev_index] = addr;
                    MY_DEBUG("devAddr[%d]=0X%02X", m38_info.dev_index, m38_info.devAddr[m38_info.dev_index]);
                    m38_info.dev_index++;
                    if(m38_info.dev_index == m38_info.dev_num && m38_info.dev_index > 0)
                    {
                        m38_info.dev_state = devRun;
                        m38_info.devLEDtime = emFlashRun;
                        m38_info.dev_flag = Info_Save;
                        // 全部设备申请完地后  保存地址等信息。
                        NVS_data_write_blob(DEV_INFO_NAMESPACE, M38_key, &m38_info, sizeof(m38_info));
                        for(uint8_t i=0; i<m38_info.dev_index; i++)
                        {
                            MY_DEBUG("devAddr[%d] = 0X%02X", i, m38_info.devAddr[i]);
                        }
                    }                                        
                }                
            }
            break;

        default:
            MY_ERROR("ERR DevType = 0X%02X", devType);
            break;
    }
}

/*--------------------------------------------------------------
 * 功能: 判断地址是否有对应的模拟设备
 * 在全部类型设备的地址里遍历一遍，并根据地址对应设备类型
 * 参数: addr 
 * 返回值: uint8_t 1找到地址 0未找到地址
----------------------------------------------------------------*/
uint8_t FindAddrInList(uint8_t addr, Dev_type_t *devType)
{
    if(devType == NULL)
    {
        return 0;
    }

    // 查找 BML04 设备
    for (int i = 0; i < BML04_MAX_NUM; i++)
    {
        if (bml04_info.devAddr[i] == addr)
        {
            *devType = simTypeML4; // 设备类型设置为 BML04
            bml04_info.dev_Addrindex = i;
            return 1;              // 找到地址，返回 1
        }
    }

    // 查找 BML12 设备
    for (int i = 0; i < BML12_MAX_NUM; i++)
    {
        if (bml12_info.devAddr[i] == addr)
        {
            *devType = simTypeML12; // 设备类型设置为 BML12
            bml12_info.dev_Addrindex = i;
            return 1;               // 找到地址，返回 1
        }
    }

    // 查找 MD8 设备
    for (int i = 0; i < MD8_MAX_NUM; i++)
    {
        if (md8_info.devAddr[i] == addr)
        {
            *devType = simTypeMD8; // 设备类型设置为 MD8
            md8_info.dev_Addrindex = i;
            return 1;              // 找到地址，返回 1
        }
    }

    // 查找 MA8 设备
    for (int i = 0; i < MA8_MAX_NUM; i++)
    {
        if (ma8_info.devAddr[i] == addr)
        {
            *devType = simTypeMA8; // 设备类型设置为 MA8
            ma8_info.dev_Addrindex = i;
            return 1;              // 找到地址，返回 1
        }
    }

    // 查找 M26 设备
    for (int i = 0; i < M26_MAX_NUM; i++)
    {
        if (m26_info.devAddr[i] == addr)
        {
            *devType = simTypeM26; // 设备类型设置为 M26
            m26_info.dev_Addrindex = i;
            return 1;              // 找到地址，返回 1
        }
    }

    // 查找 M38 设备
    for (int i = 0; i < M38_MAX_NUM; i++)
    {
        if (m38_info.devAddr[i] == addr)
        {
            *devType = simTypeM38; // 设备类型设置为 M38
            m38_info.dev_Addrindex = i;
            return 1;              // 找到地址，返回 1
        }
    }

    return 0; // 未找到地址，返回 0
}

/*--------------------------------------------------------------
 * 功能: 处理35数据帧
 * 
----------------------------------------------------------------*/
uint32_t DisposeFrame35(uint32_t COMx, void *pBuf)
{
    uint16_t i, j; // 循环
    uint8_t *pVarData = (uint8_t *)pBuf;
    struct LocalFrameDate_ST *pLocalFrameDate_st = (struct LocalFrameDate_ST *)pBuf; //
    uint16_t VarAmount = pLocalFrameDate_st->var_amount;                               // 变量个数
    uint32_t VarName;                                                                  // 变量名称
    uint32_t VarAddr;                                                                  // 目标数据在缓冲区中的偏移
    uint32_t VarLength;                                                                // 变量长度
    // uint8_t temp;
    // COMSet_ST COMSet_st_tmp;
    // uint32_t save_addr;
    struct RS485_VarName_ST *pName;
    struct RS485_VarCtrl_ST RS485_VarCtrl_st;
    VarDescription_ST VarDescription_st[64];
    struct RS485_VarName_ST *pRS485_VarName_st;
    uint8_t VarData[256];
    // uint32_t count;
    // App485Data_ST *pApp485Data_st = (App485Data_ST *)VarData;
    struct RS485_Ctrl_ST *pRS485_Ctrl_st;
    uint32_t VarLengthTotal = 0;
    uint8_t DestPort;
    // uint8_t DestAddr;
    uint8_t ReturnVarAmount = 0;
    // uint32_t u32_data;
    // struct SemVer_ST Version;
    // uint8_t DevName[16];
    uint32_t ReturnLength;
    // uint32_t PortAddrState = 1;
    //SubModeVersion_ST SubModeVersion_st;
    SubModeVersion_ST  SubModeVersion_st[2];
    // uint8_t index = 0;
    uint8_t varDev_Type = 0;    // 当前收到的通讯帧里的变量的设备类型（-B发来的帧里都指定了设备类型，但是小章鱼发的帧设备类型是0）
    uint8_t addr_flag = 0;      // 模拟的设备存在这个地址标志
    // 获取变量数据的地址
    VarAddr = 4 + sizeof(struct LocalVarDescription_ST) * VarAmount;
    // 1 逐个变量处理
    for (i = 0; i < VarAmount; i++)
    {
        VarName = pLocalFrameDate_st->LocalVarDescription_st[i].var_name;
        VarLength = pLocalFrameDate_st->LocalVarDescription_st[i].var_length;
        pName = (struct RS485_VarName_ST *)&VarName;
        
        // 指定设备类型异常，根据当前界面来选择设备类型
        if( pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeMD8 && 
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeMA8 &&
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeM38 &&
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeM26 &&
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeML4 &&
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type != emTypeML12)    
        {
            pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type = Dev_info.Dev_SCRx_type;
        }
        varDev_Type = pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type;

        // 变量名称是地址,并且是写指令
        if (pName->VarName == emVarAddr && pLocalFrameDate_st->type == emRS485Write)
        {
            MY_DEBUG("DevType = 0X%02X", varDev_Type);
            SetAddress(pLocalFrameDate_st->dest, varDev_Type);
            // 其它从设备发送给主机的,模拟设备 不会出现其他设备发送给主机
        }

        // 地址判断    
        if(pLocalFrameDate_st->dest != 0xFF)
        {
            addr_flag = FindAddrInList(pLocalFrameDate_st->dest, &varDev_Type);
            if(addr_flag == 1)
            {
                pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.Type = varDev_Type;
            }
        }        

        // MY_DEBUG("addr_flag = %d, pLocalFrameDate_st->dest=0x%02X", addr_flag, pLocalFrameDate_st->dest);
        // 发送给自己的，或者是广播帧 不用判断帧是否是发送给自己的
        if (addr_flag == 1 || pLocalFrameDate_st->dest == 0xFF)
        {
            switch (pName->VarName)
            {
                case emVarCtrl:
                    // 控制字
                    pRS485_Ctrl_st = (struct RS485_Ctrl_ST *)&pVarData[VarAddr];

                    if (pRS485_Ctrl_st->mask == 0)
                    {
                        // 重启
                        if (pRS485_Ctrl_st->rst == 1)
                        {
                            // Sys_Restart();   // 不重启
                        }
                        // 恢复出厂
                        else if (pRS485_Ctrl_st->restore == 1)
                        {
                            RestoreFactory(COMx, varDev_Type);
                        }
                    }
                    break;
                case emVarVer:
                    // 版本号, 模拟设备 主版本号默认是12345
                    VarDescription_st[ReturnVarAmount].ByteLength = 4;
                    VarDescription_st[ReturnVarAmount].VType_un.VType_st.DataForm = 1;
                    VarDescription_st[ReturnVarAmount].VType_un.VType_st.Type = varDev_Type;

                    pRS485_VarName_st = (struct RS485_VarName_ST *)&VarDescription_st[ReturnVarAmount].VarName;
                    pRS485_VarName_st->COMAddr = pLocalFrameDate_st->dest;
                    pRS485_VarName_st->VarName = emVarVer;
                    pRS485_VarName_st->Reserved = 0;
                    pRS485_VarName_st->sCOMx = COMx;
                    pRS485_VarName_st->dCOMx = 0;

                    SubModeVersion_st[1].svn = Env_st.Version.svn;
                    SubModeVersion_st[1].FPU_Type = emGD32Type;
                    SubModeVersion_st[1].DevType = varDev_Type;
                    SubModeVersion_st[1].minor = Env_st.Version.minor;
                    SubModeVersion_st[1].major = Env_st.Version.major;

                    memcpy(&VarData[VarLengthTotal], &SubModeVersion_st[1], VarDescription_st[ReturnVarAmount].ByteLength);
                    VarLengthTotal += VarDescription_st[ReturnVarAmount].ByteLength;
                    DestPort = COMx;
                    ReturnVarAmount++;
                    break;
                case emVarBootVer:
                    //boot版本号，模拟设备 boot版本号固定式12345
                    VarDescription_st[ReturnVarAmount].ByteLength = 4;
                    VarDescription_st[ReturnVarAmount].VType_un.VType_st.DataForm = 0;
                    VarDescription_st[ReturnVarAmount].VType_un.VType_st.Type = varDev_Type;

                    pRS485_VarName_st = (struct RS485_VarName_ST *)&VarDescription_st[ReturnVarAmount].VarName;
                    pRS485_VarName_st->COMAddr = pLocalFrameDate_st->dest;
                    pRS485_VarName_st->VarName = emVarBootVer;
                    pRS485_VarName_st->Reserved = 0;
                    pRS485_VarName_st->sCOMx = COMx;
                    pRS485_VarName_st->dCOMx = 0;

                    SubModeVersion_st[0].svn = 12345;
                    SubModeVersion_st[0].FPU_Type = emGD32Type;
                    SubModeVersion_st[0].DevType = varDev_Type;
                    SubModeVersion_st[0].minor = Env_st.Version.minor;
                    SubModeVersion_st[0].major = Env_st.Version.minor;
                
                    memcpy((void *)&VarData[VarLengthTotal], (void *)&SubModeVersion_st[0], VarDescription_st[ReturnVarAmount].ByteLength);

                    VarLengthTotal += VarDescription_st[ReturnVarAmount].ByteLength;
				
                    DestPort = COMx;
                    ReturnVarAmount++;
                    break;

                default:
                    // 其它
                    RS485_VarCtrl_st.COMx = COMx;
                    RS485_VarCtrl_st.RWctrl = pLocalFrameDate_st->type;
                    if (pLocalFrameDate_st->type == emRS485Write)
                    {
                        // 写设备
                        MY_DEBUG("RS485--Write");
                        Dev_info.Func_ReceiveVar(*(uint32_t *)&RS485_VarCtrl_st, (uint8_t *)&pVarData[VarAddr], &pLocalFrameDate_st->LocalVarDescription_st[i]);
                    }
                    else
                    {
                        // 读设备
                        MY_DEBUG("RS485--Read");
                        ReturnLength = 1;
                        ReturnLength = Dev_info.Func_ReceiveVarReturn(*(uint32_t *)&RS485_VarCtrl_st, 
                                                                      &VarData[VarLengthTotal], 
                                                                      &pLocalFrameDate_st->LocalVarDescription_st[i],
                                                                      &uart_addr);
                        if (ReturnLength > 0)
                        {
                            VarDescription_st[ReturnVarAmount].ByteLength = ReturnLength;
                            VarDescription_st[ReturnVarAmount].VarName = VarName;
                            VarDescription_st[ReturnVarAmount].VType_un.VType_st.DataForm = pLocalFrameDate_st->LocalVarDescription_st[i].VType_un.VType_st.DataForm;
                            VarDescription_st[ReturnVarAmount].VType_un.VType_st.Type = varDev_Type;
                            VarLengthTotal += ReturnLength;
                            DestPort = COMx;
                            ReturnVarAmount++;
                        }
                    }
                    break;
            }
        }

        VarAddr += VarLength;
    }
    if (VarLengthTotal > 0)
    {
        EditFrameLocalVar4(&VarDescription_st, VarData, ReturnVarAmount, DestPort);
    }
    return 0;
}

/**
 * 查找重复帧
 * 实际使用的时候发现A20发给M3的数据帧，M3应答慢点就会收到重复帧
 * 如果每个重复帧都导致主设备动作的话没有意义
 */
uint32_t FindHistroyFrame(FrameHead_ST *pFrameHead_st)
{
    int i;
    for (i = 0; i < MaxHistoryFrame; i++)
    {
        // 相同类型
        if (pFrameHead_st->FrameType == HistoryFrame_st[i].FrameType)
        {
            // 相同名称
            if (pFrameHead_st->FrameName == HistoryFrame_st[i].FrameName)
            {
                // 相同分片号
                if (pFrameHead_st->FrameSeg_Num == HistoryFrame_st[i].FrameSeg_Num)
                {
                    return 1;
                }
            }
        }
    }
    // 没有相同的，替换掉最老的一个帧
    for (i = 0; i < MaxHistoryFrame; i++)
    {
        if (HistoryFrame_st[i].id == 0)
        {
            HistoryFrame_st[i].FrameName = pFrameHead_st->FrameName;
            HistoryFrame_st[i].FrameSeg_Num = pFrameHead_st->FrameSeg_Num;
            HistoryFrame_st[i].FrameType = pFrameHead_st->FrameType;
            HistoryFrame_st[i].id = MaxHistoryFrame - 1;
        }
        else
        {
            HistoryFrame_st[i].id--;
        }
        debug_printf("%d,%X,%X,%X\n", HistoryFrame_st[i].id, HistoryFrame_st[i].FrameType, HistoryFrame_st[i].FrameName, HistoryFrame_st[i].FrameSeg_Num);
    }
    return 0;
}

/****************************************************************
 **描  述: 
	处理主端口接收到的数据
 **输  入: 
	
 **输  出: 
	
 **返回值: 
	
 **Date: 2021-06-17 11:20:43
 **LastEditors: Ray
 **说  明: 
 **param {uint32_t} COMx 主端口编号
*****************************************************************/
uint32_t DisposeMasterPortReceive(uint32_t COMx)
{
    FrameHead_ST *pFrameHead_st = NULL; 
    uint16_t SourceCRC, CalcCRC;          
    struct ring_buffer *ring_buf = NULL;
    uint32_t MaxFifoLength;
    uint32_t fifo_len;
    // uint32_t i;
    // uint32_t PackCheck = 1;
    static uint32_t OverTimer = 0;

    // ring_buf = ring_buf_rx[Env_st.COMSet_st[COMx].fifo_id];
    MaxFifoLength = 1024;

    // if (ring_buf == NULL)
    //     return 0;

    // fifo_len = ring_buffer_len(ring_buf);
    ESP_ERROR_CHECK(uart_get_buffered_data_len(COMx, (size_t*)&fifo_len));
    // if(fifo_len > 0)
    // {
    //     ESP_LOGI(TAG, "fifo_len = %d",fifo_len);
    // }
    
    // 超时了，200ms
    if ((_gSysClock - OverTimer) >= 20 && FrameState > 0)
    {
        ESP_LOGI(TAG, "Time OUT");
        FrameState = 0;
        NeedReadBytes = 1;
        return 1;
    }

    // 环形fifo中的数据长度少于需要的字节数，退出
    if (fifo_len < NeedReadBytes || fifo_len > MaxFifoLength)
    {
        return 1;
    }
    // 点亮界面的蓝色指示灯
    R_LED_SET(LED_ON);
    uart_read_bytes(COMx, (uint8_t *)&FrameBuf[FrameState], NeedReadBytes, 20 / portTICK_PERIOD_MS);
    // 状态判断
    switch (FrameState)
    {
    case Header_55:
        if (FrameBuf[FrameState] == 0x55)
        {
            FrameState = Header_FF;
            OverTimer = _gSysClock;
        }
        break;
    case Header_FF:
        if (FrameBuf[FrameState] == 0xFF)
        {
            FrameState = Header_FrameType;
            NeedReadBytes = 2;
        }
        else
        {
            FrameState = Header_55;
        }
        break;
    case Header_FrameType:
        FrameState = Header_FrameLength;
        NeedReadBytes = 2;
        break;
    case Header_FrameLength:
        frame_length = *(uint16_t *)&FrameBuf[FrameState];
        if (frame_length > 1000)
        {
            FrameState = Header_55;
            NeedReadBytes = 1;
        }
        else
        {
            FrameState = Header_Keyword;
            NeedReadBytes = frame_length + sizeof(FrameHead_ST) - 4;
        }
        break;
    case Header_Keyword:
        pFrameHead_st = (FrameHead_ST *)&FrameBuf[2];

        if (pFrameHead_st->FrameType == 0x09 || pFrameHead_st->FrameType == 0x35)
        {
            // CRC校验
            SourceCRC = pFrameHead_st->DataCheck;
            pFrameHead_st->DataCheck = 0;
            CalcCRC = CRCCheck(&FrameBuf[2], frame_length + sizeof(FrameHead_ST));
            // CRC错误或者分片总数超过最大分片接收能力
            if (SourceCRC != CalcCRC || pFrameHead_st->FrameSeg_Total > MaxSeqTotal)
            {
                // CRC校验失败，或者分片数超过上限
                FrameState = 0;
                NeedReadBytes = 1;
                break;
            }
            // 应答
            if (pFrameHead_st->FrameType == 0x09)
            {
                EditFrameAck(pFrameHead_st->FrameName, pFrameHead_st->FrameSeg_Num, COMx);
            }
            // 处理数据帧
            if (pFrameHead_st->FrameType == 0x09)
            {
                // 查找重复帧
                if (FindHistroyFrame(pFrameHead_st) == 1)
                {
                    FrameState = 0;
                    NeedReadBytes = 1;
                    Overtime_A20 = 0;
                    break;
                }
                // DisposeFrame(COMx, &FrameBuf[sizeof(FrameHead_ST) + 2]);
            }
            else if (pFrameHead_st->FrameType == 0x35)
            {
                ESP_LOGI(TAG, "DisposeFrame35");
                DisposeFrame35(COMx, &FrameBuf[2 + sizeof(FrameHead_ST)]);
            }
        }
        FrameState = 0;
        NeedReadBytes = 1;
        Overtime_A20 = 0;
        break;
    default:
        FrameState = 0;
        NeedReadBytes = 1;
        break;
    }
    // 熄灭界面的蓝色指示灯
    R_LED_SET(LED_OFF);
    return 0;
}


/****************************************************************
 **描  述: 
	邻元485协议从设备获取主端口地址
 **输  入: 设备类型
	
 **输  出: 
	
 **返回值: 
	
 **Date: 2024年11月14日14:06:41
 **LastEditors: wrs
 **说  明: 
*****************************************************************/
// uint8_t CurrentBaudCount[5];
int RequestAddress(uint8_t COMx, uint8_t devType)
{
    VarDescription_ST VarDescription_st[3];
    uint8_t VarData[128];
    uint8_t *temp_addr = NULL;      // 临时地址
    App485Data_ST *pApp485Data_st = (App485Data_ST *)VarData;
    struct RS485_VarName_ST *pRS485_VarName_st[3];
    SubModeVersion_ST SubModeVersion_st[2];
    //地址申请
    VarDescription_st[0].ByteLength = 4;
    VarDescription_st[0].VType_un.VType_st.DataForm = 0;
    VarDescription_st[0].VType_un.VType_st.Type = devType;
    //Boot版本号
    VarDescription_st[1].ByteLength = 4;
    VarDescription_st[1].VType_un.VType_st.DataForm = 0;
    VarDescription_st[1].VType_un.VType_st.Type = devType;
    //App版本号
    VarDescription_st[2].ByteLength = 4;
    VarDescription_st[2].VType_un.VType_st.DataForm = 0;
    VarDescription_st[2].VType_un.VType_st.Type = devType;

    switch (devType)
    {
        case emTypeML4:
            temp_addr = &bml04_info.devAddrTemp;
            break;
        case emTypeML12:
            temp_addr = &bml12_info.devAddrTemp;
            break;
        case emTypeMD8:
            temp_addr = &md8_info.devAddrTemp;
            break; 
        case emTypeMA8:
            temp_addr = &ma8_info.devAddrTemp;
            break; 
        case emTypeM26:
            temp_addr = &m26_info.devAddrTemp;
            break; 
        case emTypeM38:
            temp_addr = &m38_info.devAddrTemp;
            break; 
        default:
            // 处理未知类型
            temp_addr = NULL;
        break;      
    }

    if(temp_addr == NULL)
    {
        MY_ERROR("temp_addr is NULL");
        return 1;
    }

    if (Env_st.COMSet_st[COMx].protocol == em485 && Env_st.COMSet_st[COMx].mode == emSlave && ((*temp_addr) & 0x80) == 0x80)
    {
        (*temp_addr)++;
        if (((*temp_addr) & 0x7F) > Env_st.MaxAddr)
        {
            (*temp_addr) = 0x81;
        }

        pApp485Data_st->FlagRW = 1;
        pApp485Data_st->FlagDest = 0;
        pApp485Data_st->FlagPrint = 1;
        pApp485Data_st->Reserved = 1;
        //地址申请
        pRS485_VarName_st[0] = (struct RS485_VarName_ST *)&VarDescription_st[0].VarName;
        pRS485_VarName_st[0]->COMAddr = (*temp_addr) & 0x7F;
        pRS485_VarName_st[0]->VarName = 0x00;
        pRS485_VarName_st[0]->Reserved = 0;
        pRS485_VarName_st[0]->sCOMx = COMx;
        pRS485_VarName_st[0]->dCOMx = 0;
        //Boot版本号
        pRS485_VarName_st[1] = (struct RS485_VarName_ST *)&VarDescription_st[1].VarName;
        pRS485_VarName_st[1]->COMAddr = (*temp_addr) & 0x7F;
        pRS485_VarName_st[1]->VarName = 0x0C;
        pRS485_VarName_st[1]->Reserved = 0;
        pRS485_VarName_st[1]->sCOMx = COMx;
        pRS485_VarName_st[1]->dCOMx = 0;
        //App版本号
        pRS485_VarName_st[2] = (struct RS485_VarName_ST *)&VarDescription_st[2].VarName;
        pRS485_VarName_st[2]->COMAddr = (*temp_addr) & 0x7F;
        pRS485_VarName_st[2]->VarName = 0x04;
        pRS485_VarName_st[2]->Reserved = 0;
        pRS485_VarName_st[2]->sCOMx = COMx;
        pRS485_VarName_st[2]->dCOMx = 0;
        
        //地址申请的data就是他的VarName
        memcpy(pApp485Data_st->Data, pRS485_VarName_st[0], 4);

        //boot版本号的data
        SubModeVersion_st[0].svn = 12345;
        SubModeVersion_st[0].FPU_Type = emGD32Type;
        SubModeVersion_st[0].DevType = devType;
        SubModeVersion_st[0].minor = Env_st.Version.minor;
        SubModeVersion_st[0].major = Env_st.Version.minor;

        memcpy((pApp485Data_st->Data)+4, &SubModeVersion_st[0], 4);

        //APP版本号的data
        SubModeVersion_st[1].svn = Env_st.Version.svn;
        SubModeVersion_st[1].FPU_Type = emGD32Type;
        SubModeVersion_st[1].DevType = devType;
        SubModeVersion_st[1].minor = Env_st.Version.minor;
        SubModeVersion_st[1].major = Env_st.Version.major;
        memcpy((pApp485Data_st->Data)+8, &SubModeVersion_st[1], 4);

        // 向主设备发送地址请求帧
        EditFrameLocalVar5(&VarDescription_st, VarData, 3, COMx);

    }
    return 0;
}

#define MAX_RETRIES 5           // 最多重试次数
#define ADDRESS_TIMEOUT 30     // 超时时间 300ms
#define REQUEST_INTERVAL 20    // 申请间隔 200ms

void AutoRequestAddresses(uint8_t COMx, uint8_t devType, uint8_t devNum) 
{
    static uint8_t index = 0;
    uint8_t retries = 0;
    bool success;

    // 遍历所有设备进行地址申请
    for (uint8_t i = 0; i < devNum; i++)
    {
        retries = 0;
        success = false;

        // 尝试申请设备地址，最多重试5次
        while (retries < MAX_RETRIES)
        {
            // 调用RequestAddress函数发送申请请求
            RequestAddress(COMx, devType);
            vTaskDelay(ADDRESS_TIMEOUT);    // 等待超时
            if (index != bml04_info.dev_index)
            {
                success = true;
                MY_INFO("Device %d address successfully assigned.\n", i + 1);
                break;                  // 如果成功则跳出重试循环
            }
            retries++;
            MY_ERROR("Attempt %d failed for device %d, retrying...\n", retries, i + 1);            
        }

        if (!success)
        {
            printf("Failed to assign address to device %d after %d retries.\n", i + 1, MAX_RETRIES);
        }

       vTaskDelay(REQUEST_INTERVAL); // 超时后等待300ms
    }
}
